import { EventEmitter } from '../utils/EventEmitter';
import {
    AudioType,
    AudioState,
    AudioPlayOptions,
    AudioEventType,
    AudioEventData,
    AudioInstance as IAudioInstance
} from './types';

/**
 * 音频实例类
 * 管理单个音频的播放和控制
 */
export class AudioInstance extends EventEmitter implements IAudioInstance {
    public name: string;
    public type: AudioType;
    public state: AudioState;
    public element: HTMLAudioElement;
    public currentTime: number;
    public duration: number;
    public volume: number;
    public playbackRate: number;
    public loop: boolean;
    public muted: boolean;
    public error?: Error;
    
    private fadeTimer?: number;
    private endTime?: number;
    
    constructor(name: string, type: AudioType, element: HTMLAudioElement) {
        super();
        
        this.name = name;
        this.type = type;
        this.element = element;
        this.state = AudioState.STOPPED;
        this.currentTime = 0;
        this.duration = 0;
        this.volume = 1;
        this.playbackRate = 1;
        this.loop = false;
        this.muted = false;
        
        // 绑定事件处理器
        this.element.addEventListener('play', this.handlePlay);
        this.element.addEventListener('pause', this.handlePause);
        this.element.addEventListener('ended', this.handleEnded);
        this.element.addEventListener('timeupdate', this.handleTimeUpdate);
        this.element.addEventListener('durationchange', this.handleDurationChange);
        this.element.addEventListener('volumechange', this.handleVolumeChange);
        this.element.addEventListener('ratechange', this.handleRateChange);
        this.element.addEventListener('error', this.handleError);
    }
    
    /**
     * 播放音频
     */
    public async play(options: AudioPlayOptions = {}): Promise<void> {
        if (this.state === AudioState.ERROR) {
            throw new Error(`Cannot play audio in error state: ${this.name}`);
        }
        
        // 应用播放选项
        if (options.volume !== undefined) {
            this.setVolume(options.volume);
        }
        if (options.loop !== undefined) {
            this.setLoop(options.loop);
        }
        if (options.playbackRate !== undefined) {
            this.setPlaybackRate(options.playbackRate);
        }
        if (options.muted !== undefined) {
            this.setMuted(options.muted);
        }
        if (options.startTime !== undefined) {
            this.currentTime = options.startTime;
        }
        this.endTime = options.endTime;
        
        try {
            // 设置音频属性
            this.element.currentTime = this.currentTime;
            this.element.playbackRate = this.playbackRate;
            this.element.loop = this.loop;
            this.element.muted = this.muted;
            
            // 开始播放
            await this.element.play();
            
            // 处理淡入
            if (options.fadeIn) {
                await this.fadeIn(options.fadeIn);
            }
            
            // 处理自动播放
            if (options.autoplay) {
                this.element.play();
            }
        } catch (error) {
            const errorEvent = error as ErrorEvent;
            this.handleError(errorEvent);
            throw new Error(errorEvent.message || 'Failed to play audio');
        }
    }
    
    /**
     * 暂停音频
     */
    public pause(): void {
        if (this.state === AudioState.PLAYING) {
            this.element.pause();
            this.state = AudioState.PAUSED;
            
            this.emit(AudioEventType.PAUSE, this.createEventData());
        }
    }
    
    /**
     * 停止音频
     */
    public stop(): void {
        if (this.state !== AudioState.STOPPED) {
            this.element.pause();
            this.element.currentTime = 0;
            this.state = AudioState.STOPPED;
            
            this.emit(AudioEventType.STOP, this.createEventData());
        }
    }
    
    /**
     * 设置音量
     */
    public setVolume(volume: number, fadeTime?: number): void {
        volume = Math.max(0, Math.min(1, volume));
        
        if (fadeTime) {
            this.fadeVolume(this.volume, volume, fadeTime);
        } else {
            this.volume = volume;
            this.element.volume = volume;
            
            this.emit(AudioEventType.VOLUME_CHANGE, this.createEventData());
        }
    }
    
    /**
     * 设置播放速率
     */
    public setPlaybackRate(rate: number): void {
        rate = Math.max(0.5, Math.min(2, rate));
        this.playbackRate = rate;
        this.element.playbackRate = rate;
        
        this.emit(AudioEventType.RATE_CHANGE, this.createEventData());
    }
    
    /**
     * 设置循环
     */
    public setLoop(loop: boolean): void {
        this.loop = loop;
        this.element.loop = loop;
        
        this.emit(AudioEventType.LOOP_CHANGE, this.createEventData());
    }
    
    /**
     * 设置静音
     */
    public setMuted(muted: boolean): void {
        this.muted = muted;
        this.element.muted = muted;
        
        this.emit(AudioEventType.MUTE_CHANGE, this.createEventData());
    }
    
    /**
     * 淡入
     */
    public async fadeIn(duration: number = 1): Promise<void> {
        return this.fadeVolume(0, this.volume, duration);
    }
    
    /**
     * 淡出
     */
    public async fadeOut(duration: number = 1): Promise<void> {
        return this.fadeVolume(this.volume, 0, duration).then(() => {
            this.pause();
        });
    }
    
    /**
     * 销毁实例
     */
    public destroy(): void {
        // 移除事件监听器
        this.element.removeEventListener('play', this.handlePlay);
        this.element.removeEventListener('pause', this.handlePause);
        this.element.removeEventListener('ended', this.handleEnded);
        this.element.removeEventListener('timeupdate', this.handleTimeUpdate);
        this.element.removeEventListener('durationchange', this.handleDurationChange);
        this.element.removeEventListener('volumechange', this.handleVolumeChange);
        this.element.removeEventListener('ratechange', this.handleRateChange);
        this.element.removeEventListener('error', this.handleError);
        
        // 停止播放
        this.stop();
        
        // 清理资源
        this.element.src = '';
        this.element.load();
        
        // 清除定时器
        if (this.fadeTimer) {
            clearInterval(this.fadeTimer);
            this.fadeTimer = undefined;
        }
        
        // 移除所有事件监听器
        this.removeAllListeners();
    }
    
    /**
     * 处理播放事件
     */
    private handlePlay = (): void => {
        this.state = AudioState.PLAYING;
        this.emit(AudioEventType.PLAY, this.createEventData());
    };
    
    /**
     * 处理暂停事件
     */
    private handlePause = (): void => {
        if (this.state === AudioState.PLAYING) {
            this.state = AudioState.PAUSED;
            this.emit(AudioEventType.PAUSE, this.createEventData());
        }
    };
    
    /**
     * 处理播放结束事件
     */
    private handleEnded = (): void => {
        if (!this.loop) {
            this.state = AudioState.STOPPED;
            this.emit(AudioEventType.END, this.createEventData());
        }
    };
    
    /**
     * 处理时间更新事件
     */
    private handleTimeUpdate = (): void => {
        this.currentTime = this.element.currentTime;
        
        // 检查是否到达结束时间
        if (this.endTime !== undefined && this.currentTime >= this.endTime) {
            if (this.loop) {
                this.element.currentTime = 0;
            } else {
                this.stop();
            }
        }
    };
    
    /**
     * 处理时长变化事件
     */
    private handleDurationChange = (): void => {
        this.duration = this.element.duration;
    };
    
    /**
     * 处理音量变化事件
     */
    private handleVolumeChange = (): void => {
        this.volume = this.element.volume;
        this.muted = this.element.muted;
    };
    
    /**
     * 处理播放速率变化事件
     */
    private handleRateChange = (): void => {
        this.playbackRate = this.element.playbackRate;
    };
    
    /**
     * 处理错误事件
     */
    private handleError = (event: ErrorEvent): void => {
        this.state = AudioState.ERROR;
        this.error = new Error(event.message || 'Audio error occurred');
        
        this.emit(AudioEventType.ERROR, this.createEventData());
    };
    
    /**
     * 创建事件数据
     */
    private createEventData(): AudioEventData {
        return {
            name: this.name,
            type: this.type,
            state: this.state,
            currentTime: this.currentTime,
            duration: this.duration,
            volume: this.volume,
            playbackRate: this.playbackRate,
            loop: this.loop,
            muted: this.muted,
            error: this.error
        };
    }
    
    /**
     * 淡入淡出音量
     */
    private fadeVolume(startVolume: number, endVolume: number, duration: number): Promise<void> {
        return new Promise((resolve) => {
            if (this.fadeTimer) {
                clearInterval(this.fadeTimer);
            }
            
            const startTime = Date.now();
            const volumeDiff = endVolume - startVolume;
            
            this.emit(AudioEventType.FADE_START, this.createEventData());
            
            this.fadeTimer = window.setInterval(() => {
                const elapsed = (Date.now() - startTime) / 1000;
                const progress = Math.min(elapsed / duration, 1);
                
                const currentVolume = startVolume + volumeDiff * progress;
                this.element.volume = currentVolume;
                
                if (progress >= 1) {
                    clearInterval(this.fadeTimer);
                    this.fadeTimer = undefined;
                    this.volume = endVolume;
                    
                    this.emit(AudioEventType.FADE_COMPLETE, this.createEventData());
                    resolve();
                }
            }, 16); // 约60fps
        });
    }
} 